# 作者： 李泉志
# 2025年01月10日19时39分秒
# 2947029073@qq.com

"""
13 文件
目标
• 文件的概念
• 文件的基本操作
• 文件/文件夹的常用操作
• 文本文件的编码方式

01. 文件的概念
1.1 文件的概念和作用
    • 计算机的文件，就是存储在某种长期储存设备上的一段数据
    • 长期存储设备包括：硬盘、U 盘、移动硬盘、光盘...（非易丢失）
文件的作用:
    将数据长期保存下来，在需要的时候使用
1.2 文件的存储方式
    • 在计算机中，文件是以二进制的方式保存在磁盘上的文本文件和二进制文件
    • 文本文件
        – 可以使用文本编辑软件查看
        – 本质上还是二进制文件
        – 例如：python的源程序
    • 二进制文件
        – 保存的内容不是给人直接阅读的，而是提供给其他软件使用的
        – 例如：图片文件、音频文件、视频文件等等
        – 二进制文件不能使用文本编辑软件查看

02. 文件的基本操作
2.1 操作文件的套路
    在计算机中要操作文件的套路非常固定，一共包含三个步骤：
    1 打开文件
    2 读、写文件
        – 读将文件内容读入内存
        – 写将内存内容写入文件
    3 关闭文件

2.2 操作文件的函数/方法
    • 在Python中要操作文件需要记住1个函数和3个方法
        1) open: 打开文件，并且返回文件操作对象
        2) read: 将文件内容读取到内存
        3) write: 将指定内容写入文件
        4) close: 关闭文件
    • open函数负责打开文件，并且返回文件对象
    • read/write/close三个方法都需要通过文件对象来调用

2.3 read方法——读取文件
    • open函数的第一个参数是要打开的文件名（文件名区分大小写）
        – 如果文件存在，返回文件操作对象
        – 如果文件不存在，会抛出异常
    • read: 方法可以一次性读入并返回文件的所有内容
    • close: 方法负责关闭文件
        – 如果忘记关闭文件，会造成系统资源消耗，而且会影响到后续对文件的访问
    • 注意：read 方法执行后，会把 文件指针 移动到 文件的末尾
    提示
    • 在开发中，通常会先编写打开和关闭的代码，再编写中间针对文件的读/写操作！
    file.read(size)，size 参数代表要读取的文件内容大小

文件指针（知道）--位置指针
    • 文件指针标记从哪个位置开始读取数据
    • 第一次打开文件时，通常文件指针会指向文件的开始位置
    • 当执行了read方法后，文件指针会移动到读取内容的末尾
        – 默认情况下会移动到文件末尾
    • 思考：如果执行了一次read方法，读取了所有内容，那么再次调用read方法，还能够获得到内容吗？
        • 不能!第一次读取之后，文件指针移动到了文件末尾，再次调用不会读取到任何的内容

2.4 打开文件的方式
    • open 函数默认以只读方式打开文件，并且返回文件对象
    语法如下：
        f = open("文件名", "访问方式")
    r 以只读方式打开文件。文件的指针将会放在文件的开头，这是默认模式。如果文件不存在，抛出异常
    w 以只写方式打开文件。如果文件存在会被覆盖。如果文件不存在，创建新文件
    a 以追加方式打开文件。如果该文件已存在，文件指针将会放在文件的结尾。如果文件不存在，创建新文件进行写入
    r+ 以读写方式打开文件。文件的指针将会放在文件的开头。如果文件不存在，抛出异常(写入时，文件位置指针会跳转到尾部）
    w+ 以读写方式打开文件。如果文件存在会被覆盖。如果文件不存在，创建新文件
    a+ 以读写方式打开文件。如果该文件已存在，文件指针将会放在文件的结尾。如果文件不存在，创建新文件进行写入
"""


def open_f():
    """
    读取文件
    :return:
    """
    # mode=可以省略,默认是r，encoding要对
    file = open("file1.txt", mode="r", encoding='utf-8')
    text = file.read()
    print(text)
    file.close()


def open_rw():
    file = open('file1.txt', mode='r+', encoding='utf-8')
    text = file.read()
    print(text)
    file.write('world')  # 在指针之后写（read完后的位置）
    file.close()


def open_w():
    # file = open('file3', mode='r', encoding='utf-8')  # r模式文件不存在报错，w不存在创建
    file = open('file3', mode='w', encoding='utf-8')
    file.write('1')
    file.close()


def open_a():
    file = open('file1.txt', 'a', encoding='utf-8')
    file.write('how')  # r+模式打开后内容直接覆盖,a直接追加在最后
    file.close()


"""
2.5 按行读取文件内容
    • read 方法默认会把文件的所有内容一次性读取到内存
    • 如果文件太大，对内存的占用会非常严重
    readline方法
    • readline方法可以一次读取一行内容
    • 方法执行后，会把文件指针移动到下一行，准备再次读取
    # 打开文件
    file = open("README")
    while True:
        text = file.readline()  # 读取一行内容
        if not text:  # 判断是否读到内容
            break
        # 每读取一行的末尾已经有了一个 `\n`
        print(text, end="")
    # 关闭文件
    file.close()
    注：readline(limit) limit 参数代表要读取的文件内容大小
"""


def open_rline():
    file = open("file2.txt", mode="r", encoding='utf-8')
    while True:
        text = file.readline()  # 读取一行内容
        if not text:  # 判断是否读到内容
            break
        # 每读取一行的末尾已经有了一个 `\n`
        print(text, end="")
    file.close()


"""
2.6 文件读写案例 —— 复制文件
    小文件复制:
        • 打开一个已有文件，读取完整内容，并写入到另外一个文件
        # 1. 打开文件
        file_read = open("README")
        file_write = open("README[副本]", "w")
        # 2. 读取并写入文件
        text = file_read.read()
        file_write.write(text)
        # 3. 关闭文件
        file_read.close()
        file_write.close()
    大文件复制
    • 打开一个已有文件，逐行读取内容，并顺序写入到另外一个文件
        # 1. 打开文件
        file_read = open("README")
        file_write = open("README[复件]", "w")
        # 2. 读取并写入文件
        while True:
            # 每次读取一行
            text = file_read.readline()
            # 判断是否读取到内容
            if not text:
                break
            file_write.write(text)
        # 3. 关闭文件
        file_read.close()
        file_write.close()
"""
"""
2.7 采用 w 和 wb 模式(wb 是二进制模式)差异(请看 seek)
2.8 seek 的使用
    文件指针定位之seek方法:
    seek(offset, whence)
        offset ：文件指针偏移量(很多博客在这里将 offset 定义为指针偏移量，但是目前我的看法是这里定义为指针的相对位置)
        whence ： 0-文件开头 1-当前位置 2-文件末尾(这里的 0,1,2 只是代表了文件位置，
        而不是说 0,1,2 可以参与指针偏移的计算。from是可选项，默认为 0)
    文本模式下offset只能为非负值，往后移
    中间，或者尾部的相对位置时，只能是0
    汉字 偏移要是 3 的倍数
    二进制模式下才可以往前偏，二进制模式下offset才能为负值
"""
import os


def seek_start():
    file = open("file1.txt", mode="r+", encoding='utf-8')
    text = file.read(5)  # 读取5个字节
    print(text)
    file.seek(5, os.SEEK_SET)  # os.SEEK_SET=0，相对于文件开头读5个字节
    text = file.read(5)  # 读取5个字节
    print(text)


def seek_end():
    file = open("file1.txt", mode="r+", encoding='utf-8')
    file.seek(0, os.SEEK_END)  # os.SEEK_END=2，不能往前偏移，只能是0
    text = file.read(5)  # 相对于文件末尾读5个字节，就是空
    print(text)
    file.close()


def seek_cur():
    file = open("file1.txt", mode="r+", encoding='utf-8')
    file.seek(0, os.SEEK_CUR)  # 只能是0
    text = file.read(5)
    print(text)
    file.close()


def copy_file():  # 图片也行
    file_read = open("picture1.png", mode="rb+")
    file_write = open("picture1_copy.png", mode="wb")
    b = file_read.read()
    file_write.write(b)
    file_read.close()
    file_write.close()


if __name__ == '__main__':
    # open_f()
    # open_rw()
    # open_w()
    # open_a()
    # open_rline()
    pass
    # seek_start()
    # seek_end()
    # seek_cur()
    copy_file()
